<?php
namespace adminmatrix\plugin;
use ReflectionClass;
use ReflectionMethod;
use think\exception\HttpException;
use think\helper\Str;
use think\Response;
use adminmatrix\plugin\command\migrate\Create as PluginMigrateCreate;
use adminmatrix\plugin\command\migrate\Run as PluginMigrateRun;
use adminmatrix\plugin\command\Install as PluginInstall;
use adminmatrix\plugin\command\migrate\Rollback as PluginRollback;
use adminmatrix\plugin\command\Uninstall as PluginUninstall;
use adminmatrix\plugin\command\migrate\Status as PluginMigrateStatus;
use adminmatrix\plugin\command\PluginList;

use adminmatrix\plugin\command\make\MakeController;
use adminmatrix\plugin\command\MakePlugin;
class Service extends \think\Service
{
    protected string $pluginName;
    /**
     * 插件服务实例
     * @var PluginService
     */
    protected $pluginService;

    protected mixed $plugin_info;
    /**
     * 服务启动方法
     * 
     * 在所有服务注册完成后执行，此时可以安全地使用其他已注册的服务
     * 适合执行需要依赖其他服务的操作，如：
     * - 路由注册
     * - 中间件注册
     * - 事件监听
     * - 插件初始化
     */
    public function boot(): void
    {
        $this->app->bind("plugin.migrate.creator" , Creator::class);
        // 此处无需事件注册
        $this->commands([
            PluginMigrateCreate::class,
            PluginMigrateRun::class,

            PluginInstall::class,
            PluginRollback::class,
            PluginUninstall::class,
            PluginMigrateStatus::class,

            PluginList::class,

            MakeController::class,
            MakePlugin::class

        ]);
    }

    /**
     * 服务注册方法
     * 优先加载
     * 在服务提供者注册阶段执行，此时其他服务可能还未完全初始化
     * 适合执行基础设置和注册工作，如：
     * - 绑定服务到容器
     * - 注册命名空间
     * - 设置配置项
     * - 注册路由规则
     */
    public function register(): void
    {
        $app = $this->app->route->rule("app/:any", function ($any) {
            $this->pluginName = $any;
            # 设置 应用目录
            $this->app->setAppPath($this->app->getRootPath() . "plugins/" . $this->pluginName . DIRECTORY_SEPARATOR);
            
                    # 设置命名空间
            $this->app->setNamespace("plugins/{$any}");
            # 设置缓存目录
            $this->app->setRuntimePath($this->app->getRuntimePath() . "plugins/{$any}");

            # 读取配置信息
            $this->plugin_info = json_decode(file_get_contents($this->app->getAppPath() . "module.json") , true);
            if (!$this->plugin_info['status'])
            {
                throw new HttpException(500 , "{$this->pluginName} 插件尚未安装" );
            }

            // 加载公共文件
            if (file_exists($this->app->getAppPath() . "common.php"))
            {
                include  $this->app->getAppPath() . "common.php";
            }
            # 注册插件事件
            $this->registerPluginEvents($this->pluginName);

            // 注册当前插件的路由
            return $this->registerCurrentPluginRoutes();
        });
    }

    private function registerCurrentPluginRoutes(){
        $class = $this->getNamespace();
        $action = $this->app->request->action();
        if (class_exists($class)) {
            $instance = $this->app->invokeClass($class);
        } else {
//            $instance = $this->app->invokeClass($class);
             throw new ClassNotFoundException('class not exists:' . $class, $class);
        }

        return $this->responseWithMiddlewarePipeline($instance, $action);
    }

    protected function registerMiddleware($controller)
    {
   
        $refClass  = new ReflectionClass($controller);
        if($refClass->hasProperty("middleware"))
        {
            $middlewareProperty = $refClass->getProperty('middleware');
            $middlewareProperty->setAccessible(true);
            $instance = $refClass->newInstance($this->app);
            $middlewares = $middlewareProperty->getValue($instance);
            $action      = $this->app->request->action(true);
            foreach ($middlewares as $key => $val) {
                if(!is_int($key))
                {
                    $middleware = $val;
                    $$options = $key;
                } else if(isset($val['middleware'])){
                    $middleware = $val['middleware'];
                    $options    = $val['options'] ?? [];
                }else {
                    $middleware = $val;
                    $options    = [];
                }

                if (isset($options['only']) && !in_array($action, $this->parseActions($options['only']))) {
                    continue;
                } elseif (isset($options['except']) && in_array($action, $this->parseActions($options['except']))) {
                    continue;   
                }

                $this->app->middleware->controller($middleware);
            }


           
        }

        
    }

    protected function responseWithMiddlewarePipeline($instance, $action)
    {
        // 注册控制器中间件
        $this->registerMiddleware($instance);   
        return $this->app->middleware->pipeline('controller')
        ->send($this->app->request)
        ->then(function () use ($instance, $action) {
            // 获取当前操作名
            $suffix = $this->app->config->get('route.action_suffix');
            $action = $action . $suffix;

            if (is_callable([$instance, $action])) {
                $vars = $this->getActionBindVars();
                try {
                    $reflect = new ReflectionMethod($instance, $action);
                    // 严格获取当前操作方法名
                    $actionName = $reflect->getName();
                    if ($suffix) {
                        $actionName = substr($actionName, 0, -strlen($suffix));
                    }

                    $this->app->request->setAction($actionName);
                } catch (ReflectionException $e) {
                    $reflect = new ReflectionMethod($instance, '__call');
                    $vars    = [$action, $vars];
                    $this->app->request->setAction($action);
                }
            } else {
                // 操作不存在
                throw new HttpException(404, 'method not exists:' . $instance::class . '->' . $action . '()');
            }

            $data = $this->app->invokeReflectMethod($instance, $reflect, $vars);

            return $this->autoResponse($data);
        });
    }

    
    /**
     * 获取操作的绑定参数
     * @access protected
     * @return array
     */
    protected function getActionBindVars(): array
    {
        $bind = $this->app->config->get('route.action_bind_param');
        return match ($bind) {
            'route' => $this->app->request->param(),
            'param' => $this->app->request->param(),
            default => array_merge($this->app->request->get(), $this->app->request->param()),
        };
    }


    protected function autoResponse($data): Response
    {
        if ($data instanceof Response) {
            $response = $data;
        } elseif ($data instanceof ResponseInterface) {
            $response = Response::create((string) $data->getBody(), 'html', $data->getStatusCode());

            foreach ($data->getHeaders() as $header => $values) {
                $response->header([$header => implode(", ", $values)]);
            }
        } elseif (!is_null($data)) {
            // 默认自动识别响应输出类型
            $type     = $this->app->request->isJson() ? 'json' : 'html';
            $response = Response::create($data, $type);
        } else {
            $data = ob_get_clean();

            $content  = false === $data ? '' : $data;
            $status   = '' === $content && $this->app->request->isJson() ? 204 : 200;
            $response = Response::create($content, 'html', $status);
        }

        return $response;
    }

    protected function getNamespace(){
        $path   = $this->app->request->pathinfo();
        $path   = explode("/" , $path);
        array_shift($path);
        $plugin_name = array_shift($path);
        
        $str = array_shift($path) ?? 'index';
        $controller = preg_replace_callback('/(.*?)(\.([^.]+))?$/', function ($matches) {
            if (isset($matches[3])) {
                return $matches[1]. '/' . ucfirst($matches[3]);
            }
            return ucfirst($matches[1]);
        }, $str);
        
        $controller = $controller ? str_replace(".",'/',$controller) : "Index";

        $action = array_shift($path) ?? "index";
        # 设置控制器
        $this->app->request->setController($controller);

        # 设置 方法
        $this->app->request->setAction($action);
        # 完整地址
        if($this->app->config->get('route.controller_suffix'))
        {
            $namespace =  $this->app->getNamespace() ."/" . "controller/" . str_replace("/","\\",$controller) . "Controller";
        }else{
            $namespace = $this->app->getNamespace() ."/" . "controller/" . str_replace("/","\\",$controller);
        }


        return str_replace("/","\\" , $namespace);
    }

    protected function registerPluginEvents($pluginName)
    {
        $eventFile = $this->app->getRootPath() . "plugins/{$pluginName}/event.php";
        if (file_exists($eventFile)) {
            $events = include $eventFile;
            if (is_array($events)) {
                foreach ($events as $eventName => $listeners) {
                    foreach ((array)$listeners as $listener) {
                        $this->app->event->listen($eventName, $listener);
                    }
                }
            }
        }
    }

}